package com.adnaan.backend.config;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;

/**
 * author: adnaan
 * create: 2025-01-05 17:20
 * Description:
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {

    // 允许跨域的域名
    private final String allowedOrigin = "http://admin.adnaan.cn";
    @Value("${storage.local.path}")
    private String uploadFolder;
    @Value("${storage.local.domain}")
    private String uploadUrl;

    // 注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册 Sa-Token 拦截器，校验规则为 StpUtil.checkLogin() 登录校验。
        registry.addInterceptor(new SaInterceptor(handle -> {
            SaRouter.match("/**")
                    .notMatch(
                            "/favicon.ico",
                            "/doc.html",
                            "/v3/api-docs/**",
                            "/webjars/**",
                            "/profile/**"  // 添加静态资源路径到白名单
                    )
                    .check(StpUtil::checkLogin);
        })).addPathPatterns("/**");
    }

    /**
     * 路径和服务器上的路径进行对应
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /* *
         * 本地文件上传路径
         * */
        registry.addResourceHandler(uploadUrl + "/**")  // 使用固定的访问路径
                .addResourceLocations("file:" + uploadFolder + "/")
                .resourceChain(true)
                .addResolver(new PathResourceResolver());
    }

    /**
     * 跨域
     *
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin(allowedOrigin);
        // 明确指定允许的请求头
        config.addAllowedHeader("authorization");
        config.addAllowedHeader("content-type");
        config.addAllowedHeader("x-requested-with");
        config.addAllowedHeader("token");
        config.addAllowedMethod("*");
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return new CorsFilter(source);
    }

    /**
     * 注册 [Sa-Token全局过滤器]
     * description: 全局过滤器，拦截所有请求
     */
    @Bean
    public SaServletFilter saServletFilter() {
        return new SaServletFilter()
                // 前置拦截：在路由匹配之前执行
                .setBeforeAuth(obj -> {
                    SaHolder.getResponse()
                            .setHeader("Access-Control-Allow-Origin", allowedOrigin)
                            .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                            .setHeader("Access-Control-Max-Age", "3600")
                            .setHeader("Access-Control-Allow-Headers", "authorization, content-type, x-requested-with, token")
                            .setHeader("Access-Control-Allow-Credentials", "true");
                    // 跨域时会首先发送一个option请求，这里给option请求直接返回正常状态
                    SaRouter.match(SaHttpMethod.OPTIONS).back();
                });
    }

    @Bean
    public ErrorPageRegistrar errorPageRegistrar() {
        return registry -> {
            // 404 错误页面
            ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/error");
            // 500 错误页面
            ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error");
            registry.addErrorPages(error404Page, error500Page);
        };
    }
}
